kotlin Android day

kotlin 匿名 与 具名 函数使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fun main() {
//匿名函数
showInfo("lr", "男", 29) {
println("$it")
}
//具名函数
showInfo("lr", "男", 29, ::showResultImpl)
}

fun showResultImpl(result: String) {
println(result)
}

inline fun showInfo(name: String, sex: String, age: Int, showResult: (String) -> Unit) {
val str = "显示信息 name = ${name} , sex = ${sex} , age = ${age}"
showResult(str)
}

Java的实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ClassTest {


public static void main(String[] args) {

//匿名实现方式
showInfo("lr", "男", 29, new ShowResult() {

@Override
public void show(String text) {
System.out.println(text);
}
});

//具体实现方式
ShowResultImpl showResult = new ShowResultImpl();
showInfo("lr", "男", 29, showResult);
}


static class ShowResultImpl implements ShowResult {

@Override
public void show(String text) {
System.out.println(text);
}
}

public static void showInfo(String name, String sex, int age, ShowResult showResult) {
String value = "显示信息 name = " + name + " , sex = " + sex + " , age = " + age;
showResult.show(value);
}


interface ShowResult {
void show(String text);
}
}

【?】 安全调用操作符

1
2
3
4
5
6
7
8

var lr : String? = " I'm wang "

lr = null

lr?.capitalize()// lr是可空类型 可能是null 想要使用lr 必须给出补救措施

lr?.capitalize()// lr是可空类型 如果真的是null ?.后面的函数不执行,就不会引起空指针异常

【if】 安全调用操作符

1
2
3
4
5
6
7
8
9
10

var lr: String? = " I'm wang "

lr = null

if (lr != null) {
val r = lr.capitalize()
} else {
println(lr)
}

【?:】 空合并操作符号

1
2
3
4
5
6
7
8
9
10

var lr: String? = " I'm wang "

lr = null

//空合并操作符
println(lr ?: "I'm wang ")//如果lr等于null 就会执行?:后面的区域

//let函数 + 空合并操作符
println(lr ?.let{ "[$it]" } ?: "I'm wang")//如果lr等于null 则不会执行.let{}函数 会执行?:后面的区域

【!!】 非空断言操作符

1
2
3
4
5
6
7
8
9

var lr : String? = null

lr = " I'm wang "

//lr是可空类型 可能是null 想要使用lr 必须给出补救措施
val r = lr!!.capitalize()// !!断言 不管lr是不是null 都执行,这个和java一样

//如果百分百保证lr是有值,那么才可以使用断言!!

【let】 安全调用

1
2
3
4
5
6
7
8
9
10
11
12
var lr: String? = null
lr = " I'm wang "
//lr是可空类型 如果真的是null ?.后面的函数不执行,就不会引起空指针异常
lr?.let {
it == lr
//如果能够执行这里 it一定不为null
if (lr.isBlank()) {
"Default"
} else {
it
}
}

【substring】截取字符串

1
2
3
4
5
6
7
8
9
10
11
val subStr = "I'm lr"
val indexOf = subStr.indexOf(' ')
println(subStr.substring(0, indexOf))
println(subStr.substring(0 until indexOf))

//输出如下

I'm
I'm

Process finished with exit code 0

【split】分割字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val splitStr = "I'm,lr,wang,kotlin"
//splist 自动类型推断成 list = List<String>
val splist = splitStr.split(",")
println("分割后的list里面的元素有 ${splist}")

//C++ 解构 kt解构
val (v1, v2, v3, v4) = splist
println("解构四个只读变量值是 ${v1}, ${v2}, ${v3}, ${v4}")

//输出如下

分割后的list里面的元素有 [I'm, lr, wang, kotlin]
解构四个只读变量值是 I'm, lr, wang, kotlin

Process finished with exit code 0

Process finished with exit code 0

【replace】字符串完成加解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
val sourcePwd = "ABCDEFGHIJKL"
println("加密前处理 字符串 ${sourcePwd}")

val r = sourcePwd.replace(Regex("[ACEGI]")) {
it.value
when (it.value) { //处理每一个字符
"A" -> "1"
"C" -> "2"
"E" -> "3"
"G" -> "4"
"I" -> "5"
else -> it.value //返回原始字符
}
}
println("加密后处理 字符串 ${r}")


val r1 = r.replace(Regex("[12345]")) {
it.value
when (it.value) { //处理每一个字符
"1" -> "A"
"2" -> "C"
"3" -> "E"
"4" -> "G"
"5" -> "I"
else -> it.value //返回原始字符
}
}

println("解密后处理 字符串 ${r1}")

加密前处理 字符串 ABCDEFGHIJKL
加密后处理 字符串 1B2D3F4H5JKL
解密后处理 字符串 ABCDEFGHIJKL

Process finished with exit code 0

【== ===】比较操作

// == 值 内容比较 相当于java的equals
// === 引用的比较

【apply】内置函数

.apply返回的是自己本身 大部分的匿名函数都会返回it 而apply是持有this == 自己本身

【let】内置函数

.let 匿名函数末尾行则作为返回值 let特点 返回类型: 根据函数末尾行返回的变化而变化

let方式 + 空合并操作符 对值判null,并返回

1
2
3
4
5
6
7
8
9
10
11
fun loginApp(acc: String, pwd: String): Boolean {
if (checkText(acc, "请输入账户") == "-1") return false
if (checkText(pwd, "请输入密码") == "-1") return false
return true
}

fun checkText(text: String, hint: String): String {
return text?.let {
"-1"
} ?: hint
}

【run】内置函数

.run 根据函数末尾行返回的变化而变化 而run是持有this == 自己本身

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

//输出
"请输入的信息必须是中文"
.run(::isChinese)
.run(::isHint)
.run(::println)

//取得返回值
var str: String = "请输入的信息必须是中文"
.run(::isChinese)
.run(::isHint)
.run(::isRuHint)

fun isChinese(text: String): Boolean {
val reg = "[\\u4e00-\\u9fa5]".toRegex()
return reg.containsMatchIn(text)
}

fun isNumber(bol: Boolean): String {
return if (bol) "-1" else "请输入的信息必须是中文"
}

fun isRuHint(str: String): String {
return "[$str]"
}

主构造函数

规范化写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// _xxx都是 临时输入类型不能直接引用 需要临时变量接收
class PersonInfo(_name: String, _age: String, _job: String) {

private var name = _name
private set(value) {
field = value
}
private var age = _age
private set(value) {
field = value
}
private var job = _job
private set(value) {
field = value
}

fun show() {
println("$name ,$age , $job,")
}
}

主构造函数里得属性

1
2
3
4
5
6
7
//  var name  就相当于   private var name = _name   的写法  得简洁写法
class PersonInfo(var name: String, var age: String, var job: String) {

fun show() {
println("$name ,$age , $job,")
}
}

次构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class PersonInfo(name: String) {

constructor(name: String, age: String) : this(name) {
println("2个参数的次构造函数 name:$name ,sex:$age")
}

constructor(name: String, age: String, job: String) : this(name) {
println("3个参数的次构造函数 name:$name ,sex:$age ,job:$job")
}
}

val lr = PersonInfo("lr")
PersonInfo("lr", "16")
PersonInfo("lr", "16", "A股")

//输出

2个参数的次构造函数 name:lr ,sex:16
3个参数的次构造函数 name:lr ,sex:16 ,job:A股

构造函数默认参数

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class PersonInfo(_name: String, _age: String, _job: String) {

//此次与Java对比 不是Java的static{}
//是相当于Java的{}代 码块
init { //1
println("主构造函数被调用了...")
}

constructor(nickName: String) : this(nickName, "19", "A") {
println("次构造函数被调用了...")//2
}
}


PersonInfo("lr", "1", "job")
println("...")
PersonInfo("io")

//答应你打印顺序为
主构造函数被调用了...
...
主构造函数被调用了...
次构造函数被调用了...

函数执行顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//第一步生成val job: String
class PersonInfo(_name: String, _age: String, val _job: String) {

//第二步:生成val job
val job = _job

//此次与Java对比 不是Java的static{}
//是相当于Java的{}代 码块
init { //1
val jobValue = _job //第三步:生成jobValue细节
println("主构造函数被调用了...$jobValue")
}

//次构造函数
constructor(nickName: String) : this(nickName, "19", "A") {
//第四步: 生成次构造的细节
println("次构造函数被调用了...")//2
}
}


二三步骤是并行的 成员与init是同时生成的
//细节 因为 val job = _job 在init前之前所以就会先生成,再到init。

延迟初始化lateinit学习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class LateinitClass {
lateinit var job: String


fun request() {
job = "编程"
}

fun showResponseResult() {

//处理技巧
if (::job.isInitialized) println("showResponseResult $job") else println("你都没有初始化加载 ")

//输出
println("showResponseResult $job")
}
}


//执行就会报错
var lc = LateinitClass()
lc.showResponseResult()

//正确方式
var lc = LateinitClass()
lc.request()
lc.showResponseResult()

Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property job has not been initialized
at test.kotlin.LateinitClass.showResponseResult(ktFunction.kt:128)
at test.kotlin.KtFunctionKt.main(ktFunction.kt:115)
at test.kotlin.KtFunctionKt.main(ktFunction.kt)

因为你还没初始化 lateinit var job: String 就开始使用了。

惰性初始化 by lazay

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

class ByLazyClass {

val dataBaseData1 = readSQLServerDatabase()//01

val dataBaseData by lazy {

readSQLServerDatabase()
}

private fun readSQLServerDatabase() {
println("开始启动操作......")
println("加载读取操作......")
println("加载读取操作......")
println("加载读取操作......")
println("加载读取操作......")
println("加载读取操作......")
println("结束所有操作......")
}
}
//构建时候不会加载
var bylazy = ByLazyClass() //此次构建得时候会执行 01处代码
//开始使用才会加载
bylazy.dataBaseData

初始化常见陷阱问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14

//问题一

class TextClass(_info: String) {

//如下会报错 因为kotlin会严格按顺序执行下来的。
// variable cannot be initialized before declaration
//声明前不能初始化变量

init {
number = number.times(9)
}
private var number = 9
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

//问题二

class TextClass() {

private val info: String //01

init { //02
getInfoMethod()
info = "DerryOk"
}

fun getInfoMethod() { //03
println("info:${info[0]}")
}

}

//执行会报错 因为 TextClass()时候就会执行 02块 然后info还没被初始化就引用就会报错

TextClass().getInfoMethod()


Exception in thread "main" java.lang.NullPointerException
at test.kotlin.TextClass.getInfoMethod(ktFunction.kt:134)
at test.kotlin.TextClass.<init>(ktFunction.kt:129)
at test.kotlin.KtFunctionKt.main(ktFunction.kt:120)
at test.kotlin.KtFunctionKt.main(ktFunction.kt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

//问题三

class TextClass(_info: String) {
val content: String = getInfoMethod() //01

private val info = _info //02

private fun getInfoMethod() = info //03
}

println("内容的长度:${TextClass("test").content.length}")

//执行就会报错
Exception in thread "main" java.lang.NullPointerException
at test.kotlin.KtFunctionKt.main(ktFunction.kt:118)
at test.kotlin.KtFunctionKt.main(ktFunction.kt)


//因为调用.content时候会执行 03 再执行 02 这时候info还未被初始化。
解决方法就是将 02 与 01 顺序调换

kotlin的 继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

//Kt所有的类,默认是final修饰的,不能被继承 与Java相反
//通过关键字 open:移除final修饰
open class PersonInfo(private val name: String) {

fun showName() = "父类 的姓名是 $name"

open fun outInfo() = println(showName())
}

class Student(private val subName: String) : PersonInfo(subName) {

private fun showName() = "子类 的姓名是 $subName"

override fun outInfo() = println(showName())
}



//返回父类的引用 调用则返回是子类实现 因为重写了方法
val personInfo: PersonInfo = Student("lr")
personInfo.outInfo()

kotlin类型转换 【 is + as 】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//Kt所有的类,默认是final修饰的,不能被继承 与Java相反
//通过关键字 open:移除final修饰
open class PersonInfo(private val name: String) {

fun showName1() = "父类 的姓名是 $name"

open fun outInfo() = println(showName1())
}

class Student(private val subName: String) : PersonInfo(subName) {

private fun showName() = "子类 的姓名是 $subName"

override fun outInfo() = println(showName())
}



val personInfo: PersonInfo = Student("lr")
personInfo.outInfo()

if(personInfo is Student){
(personInfo as Student).outInfo()
}


if (personInfo is Student) {
(personInfo as Student).outInfo()
}
if (personInfo is PersonInfo) {
println ((personInfo as PersonInfo).showName1())
}



//输出

子类 的姓名是 lr
父类 的姓名是 lr

Kotlin 序列化Parcelable/Serializable

Parcelable

1.添加配置
app目录下的build.gradle文件

1
2
3
4
5
6
android {
...
androidExtensions {
experimental = true
}
}

2.添加注解并实现Parcelable
@Parcelize
data class User(val name: String) : Parcelable

完成序列化操作

3.泛型序列化

1
2
3
4
5
6
@Parcelize
data class BaseBean<T : Parcelable>(
val errorMsg: String,
val errorCode: Int,
val data: T
) : Parcelable

这里需要注意的是泛型也要实现Parcelable,即

Parcelable源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface Parcelable {
int CONTENTS_FILE_DESCRIPTOR = 1;
int PARCELABLE_WRITE_RETURN_VALUE = 1;

int describeContents();

void writeToParcel(Parcel var1, int var2);

public interface Creator<T> {
T createFromParcel(Parcel var1);

T[] newArray(int var1);
}

public interface ClassLoaderCreator<T> extends Parcelable.Creator<T> {
T createFromParcel(Parcel var1, ClassLoader var2);
}
}

可以看到还是有writeToParcel方法和Creator等,其实也没少,只是不再需要我们去写了。

Serializable

Serializable的方式比较简单,直接实现Serializable就可以了

1
2
3
4
data class User(
val id: Int,
val name: String
) : Serializable